// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2016-2019, LomboTech Co.Ltd.
 * Author: lomboswer <lomboswer@lombotech.com>
 *
 * memctrl dev driver - device of LomboTech Memctrl Controller
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <linux/of.h>

#include <mach/debug.h>
#include <mach/common.h>
#include "memctrl.h"
#include "memctrl_conf.h"
#include "memctrl_dev.h"

/* redefine mode name, for PTR_XXX */
#undef MOD_NAME
#define MOD_NAME	"MEMCTRl_DEV"

const struct data_unit data_units[] = {
	{
		"B",
		1
	},
	{
		"KB",
		1024
	},
	{
		"MB",
		1024 * 1024
	}
};

const struct data_unit_array data_unit_array = {
	.data_units = data_units,
	.array_size = ARRAY_SIZE(data_units),
};

const struct cfg_unit flaw_units[] = {
	{
		"1",
		MEMCTRL_UNIT_1B,
		1
	},
	{
		"16",
		MEMCTRL_UNIT_16B,
		16
	},
	{
		"64",
		MEMCTRL_UNIT_64B,
		64
	},
	{
		"256",
		MEMCTRL_UNIT_256B,
		256
	},
	{
		"1K",
		MEMCTRL_UNIT_1KB,
		1024
	},
	{
		"4K",
		MEMCTRL_UNIT_4KB,
		4096
	},
	{
		"64K",
		MEMCTRL_UNIT_64KB,
		64 * 1024
	},
	{
		"128K",
		MEMCTRL_UNIT_128KB,
		128 * 1024
	}
};

const struct flaw_unit_array flaw_unit_array = {
	.flaw_units = flaw_units,
	.array_size = ARRAY_SIZE(flaw_units),
};

const struct cfg_unit sample_units[] = {
#if defined(CONFIG_ARCH_LOMBO_N7V5) || defined(CONFIG_ARCH_LOMBO_N5V1) \
	|| defined(CONFIG_ARCH_LOMBO_N7V7)
	{
		"100us",
		MEMCTRL_SAMPLE_100US,
		100,
		1,
		"us"
	},
#endif
	{
		"1ms",
		MEMCTRL_SAMPLE_1MS,
		1,
		1,
		"ms"
	},
	{
		"10ms",
		MEMCTRL_SAMPLE_10MS,
		10,
		1,
		"ms"
	},
	{
		"100ms",
		MEMCTRL_SAMPLE_100MS,
		100,
		1,
		"ms"
	},
	{
		"1s",
		MEMCTRL_SAMPLE_1S,
		1000,
		1000,
		"s"
	},
	{
		"10s",
		MEMCTRL_SAMPLE_10S,
		10000,
		1000,
		"s"
	}
};

const struct sample_unit_array sample_unit_array = {
	.sample_units = sample_units,
	.array_size = ARRAY_SIZE(sample_units),
};

#ifdef CONFIG_ARCH_LOMBO_N7V1
const struct channel_info master_channels[] = {
	{
		"CPU",
		MEMCTRL_CPU
	},
	{
		"VC",
		MEMCTRL_VC
	},
	{
		"AX",
		MEMCTRL_AX0
	},
	{
		"VISS0",
		MEMCTRL_VISS
	},
	{
		"VISS1",
		MEMCTRL_VISS1
	},
	{
		"DPU",
		MEMCTRL_DPU
	},
	{
		"DMA",
		MEMCTRL_DMA
	}
};
#elif defined CONFIG_ARCH_LOMBO_N7V3
const struct channel_info master_channels[] = {
	{
		"CPU",
		MEMCTRL_CPU
	},
	{
		"MPEG",
		MEMCTRL_MPEG
	},
	{
		"AX0",
		MEMCTRL_AX0
	},
	{
		"VISS",
		MEMCTRL_VISS
	},
	{
		"DPU",
		MEMCTRL_DPU
	},
	{
		"DMA",
		MEMCTRL_DMA
	},
	{
		"GMAC0",
		MEMCTRL_GMAC0
	},
	{
		"VGSS",
		MEMCTRL_VGSS
	},
	{
		"IVX",
		MEMCTRL_IVX
	},
	{
		"CE",
		MEMCTRL_CE
	},
	{
		"HVC",
		MEMCTRL_HVC
	},
	{
		"I2C4", /* others must at the last */
		MEMCTRL_I2C4
	},
};
#elif (defined CONFIG_ARCH_LOMBO_N7V5) || (defined CONFIG_ARCH_LOMBO_N5V1) \
	|| (defined CONFIG_ARCH_LOMBO_N7V7)
const struct channel_info master_channels[] = {
	{
		"CPU",
		MEMCTRL_CPU
	},
#ifndef CONFIG_ARCH_LOMBO_N7V7
	{
		"MJPEG",
		MEMCTRL_MJPEG
	},
#endif
	{
		"AX0",
		MEMCTRL_AX0
	},
	{
		"VISS",
		MEMCTRL_VISS
	},
	{
		"DPU",
		MEMCTRL_DPU
	},
	{
		"DMA",
		MEMCTRL_DMA
	},
	{
		"GMAC0",
		MEMCTRL_GMAC0
	},
	{
		"VGSS",
		MEMCTRL_VGSS
	},
	{
		"IVX",
		MEMCTRL_IVX
	},
	{
		"CE",
		MEMCTRL_CE
	},
#ifdef CONFIG_ARCH_LOMBO_N7V7
	{
		"HVX",
		MEMCTRL_HVX
	},
#else
	{
		"I2CCQI",
		MEMCTRL_I2CCQI
	},
#endif
};
#elif (defined CONFIG_ARCH_LOMBO_N9V1)
const struct channel_info master_channels[] = {
	{
		"CPU",
		MEMCTRL_CPU
	},
	{
		"VC",
		MEMCTRL_VC
	},
	{
		"AX0",
		MEMCTRL_AX0
	},
	{
		"VISS",
		MEMCTRL_VISS
	},
	{
		"DPU",
		MEMCTRL_DPU
	},
	{
		"DMA",
		MEMCTRL_DMA
	},
	{
		"VDC",
		MEMCTRL_VDC
	},
	{
		"GMAC0",
		MEMCTRL_GMAC0
	},
	{
		"VGSS",
		MEMCTRL_VGSS
	},
	{
		"IVX",
		MEMCTRL_IVX
	},
	{
		"GPU",
		MEMCTRL_GPU
	},
	{
		"GMAC1",
		MEMCTRL_GMAC1
	},
	{
		"CE",
		MEMCTRL_CE
	},
	{
		"AX1",
		MEMCTRL_AX1
	},
	{
		"HVC",
		MEMCTRL_HVC
	},
	{
		"USB3_0",
		MEMCTRL_USB3_0
	},
	{
		"USB3_1",
		MEMCTRL_USB3_1
	},
};
#elif (defined CONFIG_ARCH_LOMBO_N9V3)
const struct channel_info master_channels[] = {
	{
		"CPU",
		MEMCTRL_CPU
	},
	{
		"VC",	/* MJPEG */
		MEMCTRL_VC
	},
	{
		"AX",
		MEMCTRL_AX
	},
	{
		"VISS",
		MEMCTRL_VISS
	},
	{
		"DPU",
		MEMCTRL_DPU
	},
	{
		"DMA",
		MEMCTRL_DMA
	},
	{
		"GMAC0",
		MEMCTRL_GMAC0
	},
	{
		"VGSS",
		MEMCTRL_VGSS
	},
	{
		"IVX",
		MEMCTRL_IVX
	},
	{
		"GMAC1",
		MEMCTRL_GMAC1
	},
	{
		"CE",
		MEMCTRL_CE
	},
	{
		"HVC",
		MEMCTRL_HVC
	},
	{
		"USB3_0",
		MEMCTRL_USB3_0
	},
	{
		"USB2_SDC_SPI",
		MEMCTRL_USB2_SDC_SPI
	},
	{
		"PCIE0",
		MEMCTRL_PCIE0
	},
	{
		"PCIE1",
		MEMCTRL_PCIE1
	},
	{
		"SATA",
		MEMCTRL_SATA
	},
};
#endif

const struct channel_info_array channel_info_array = {
	.master_channels = master_channels,
	.array_size = ARRAY_SIZE(master_channels),
};

#ifdef CONFIG_ARCH_LOMBO_N7V1
const struct master_info memtrl_master_prio[] = {
	{
		.priority_root = {
			.reg_offset = 0,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.name = {
			"CPU",
		},
		.master_num = 1,
	},
	{
		.priority_root = {
			.reg_offset = 0xb0,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.priority_sub = {
			{
				.reg_offset = 0x10,
				.bit_offset = 0x0,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x10,
				.bit_offset = 0x4,
				.bit_mask = 0x7,
			},
		},
		.name = {
			"VC",
			"VDC",
		},
		.master_num = 2,
	},
	{
		.priority_root = {
			.reg_offset = 0x160,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.name = {
			"AX",
		},
		.master_num = 1,
	},
	{
		.priority_root = {
			.reg_offset = 0x210,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.name = {
			"VISS0",
		},
		.master_num = 1,
	},
	{
		.priority_root = {
			.reg_offset = 0x2c0,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.name = {
			"VISS1",
		},
		.master_num = 1,
	},
	{
		.priority_root = {
			.reg_offset = 0x370,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.name = {
			"DPU",
		},
		.master_num = 1,
	},
	{
		.priority_root = {
			.reg_offset = 0x420,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.priority_sub = {
			{
				.reg_offset = 0x20,
				.bit_offset = 0x0,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x20,
				.bit_offset = 0x4,
				.bit_mask = 0x7,
			},
		},
		.name = {
			"DMA",
			"GMAC",
		},
		.master_num = 2,
	},
	{
		.priority_root = {
			.reg_offset = 0x4d0,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.name = {
			"USB",
		},
		.master_num = 1,
	},
	{
		.priority_root = {
			.reg_offset = 0x580,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.name = {
			"SDC0_2",
		},
		.master_num = 1,
	},
	{
		.priority_root = {
			.reg_offset = 0x630,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.name = {
			"SDC1",
		},
		.master_num = 1,
	},
};
#elif defined(CONFIG_ARCH_LOMBO_N7V3) || defined(CONFIG_ARCH_LOMBO_N7V5) \
	|| defined(CONFIG_ARCH_LOMBO_N5V1) || defined(CONFIG_ARCH_LOMBO_N7V7)
const struct master_info memtrl_master_prio[] = {
	{ /* M0 */
		.priority_root = {
			.reg_offset = 0,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.name = {
			"CPU",
		},
		.master_num = 1,
	},
	{ /* M1 */
		.priority_root = {
			.reg_offset = 0x10,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.priority_sub = {
#ifndef CONFIG_ARCH_LOMBO_N7V7
			{
				.reg_offset = 0x10,
				.bit_offset = 0x0,
				.bit_mask = 0x7,
			},
#endif
			{
				.reg_offset = 0x10,
				.bit_offset = 0x4,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x10,
				.bit_offset = 0x8,
				.bit_mask = 0x7,
			},
		},
		.qos_sr_root = {
			.reg_offset = 0x14,
			.bit_offset = 0,
			.bit_mask = 0x7,
			.rd_reg_offset = 0x18,
		},
		.qos_sr_sub = {
#ifndef CONFIG_ARCH_LOMBO_N7V7
			{
				.reg_offset = 0x14,
				.bit_offset = 0,
				.bit_mask = 1,
				.rd_bit_offset = 0,
			},
#endif
			{
				.reg_offset = 0x14,
				.bit_offset = 1,
				.bit_mask = 1,
				.rd_bit_offset = 4,
			},
			{
				.reg_offset = 0x14,
				.bit_offset = 2,
				.bit_mask = 1,
				.rd_bit_offset = 8,
			},
		},
		.name = {
#ifndef CONFIG_ARCH_LOMBO_N7V7
			"MJPEG",
#endif
			"VGSS",
			"IVX",
		},
#ifndef CONFIG_ARCH_LOMBO_N7V7
		.master_num = 3,
#else
		.master_num = 2,
#endif
	},
	{ /* M2 */
		.priority_root = {
			.reg_offset = 0x20,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.name = {
			"AX0",
		},
		.master_num = 1,
	},
	{ /* M3 */
		.priority_root = {
			.reg_offset = 0x30,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.name = {
			"VISS",
		},
		.master_num = 1,
	},
	/* M4 RSVD */
	{
	},
	{ /* M5 */
		.priority_root = {
			.reg_offset = 0x50,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.name = {
			"DPU",
		},
		.master_num = 1,
	},
	{ /* M6 */
		.priority_root = {
			.reg_offset = 0x60,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.priority_sub = {
			{
				.reg_offset = 0x20,
				.bit_offset = 0,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x20,
				.bit_offset = 4,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x20,
				.bit_offset = 11,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x20,
				.bit_offset = 16,
				.bit_mask = 0x7,
			},
		},
		.qos_sr_root = {
			.reg_offset = 0x24,
			.bit_offset = 0,
			.bit_mask = 0x1B,
			.rd_reg_offset = 0x28,
		},
		.qos_sr_sub = {
			{
				.reg_offset = 0x24,
				.bit_offset = 0,
				.bit_mask = 1,
				.rd_bit_offset = 0,
			},
			{
				.reg_offset = 0x24,
				.bit_offset = 1,
				.bit_mask = 1,
				.rd_bit_offset = 4,
			},
			{
				.reg_offset = 0x24,
				.bit_offset = 3,
				.bit_mask = 1,
				.rd_bit_offset = 12,
			},
			{
				.reg_offset = 0x24,
				.bit_offset = 4,
				.bit_mask = 1,
				.rd_bit_offset = 16,
			},
		},
		.name = {
			"DMA",
			"GMAC0",
#if defined(CONFIG_ARCH_LOMBO_N7V5) || defined(CONFIG_ARCH_LOMBO_N5V1) \
	|| defined(CONFIG_ARCH_LOMBO_N7V7)
			"I2CCQI",
#elif defined(CONFIG_ARCH_LOMBO_N7V3)
			"I2C4",
#endif
			"CE",
		},
		.master_num = 4,
	},
	/* M7 */
	{
	},
	{ /* M8 */
		.priority_root = {
			.reg_offset = 0x80,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.qos_sr_root = {
			.reg_offset = 0x34,
			.bit_offset = 0,
			.bit_mask = 0x1,
			.rd_reg_offset = 0x38,
		},
		.qos_sr_sub = {
			{
			.reg_offset = 0x34,
			.bit_offset = 0,
			.bit_mask = 0x1,
			.rd_bit_offset = 0,
			}
		},
#ifndef CONFIG_ARCH_LOMBO_N7V7
		.name = {
			"HVC",
		},
#else
		.name = {
			"HVX",
		},
#endif
		.master_num = 1,
	},
	{ /* M9 */
		.priority_root = {
			.reg_offset = 0x90,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.priority_sub = {
			{
				.reg_offset = 0x40,
				.bit_offset = 0,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x40,
				.bit_offset = 4,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x40,
				.bit_offset = 8,
				.bit_mask = 0x7,
			},
#if defined(CONFIG_ARCH_LOMBO_N7V3)
			{
				.reg_offset = 0x40,
				.bit_offset = 16,
				.bit_mask = 0x7,
			},
#endif
#if defined(CONFIG_ARCH_LOMBO_N7V7)
			{
				.reg_offset = 0x40,
				.bit_offset = 12,
				.bit_mask = 0x7,
			},
#endif
			{
				.reg_offset = 0x40,
				.bit_offset = 20,
				.bit_mask = 0x7,
			},
#if defined(CONFIG_ARCH_LOMBO_N7V7)
			{
				.reg_offset = 0x40,
				.bit_offset = 12,
				.bit_mask = 0x7,
			},
#endif
		},
		.qos_sr_root = {
			.reg_offset = 0x44,
			.bit_offset = 0,
			.bit_mask = 0x2F,
			.rd_reg_offset = 0x48,
		},
		.qos_sr_sub = {
			{
				.reg_offset = 0x44,
				.bit_offset = 0,
				.bit_mask = 1,
				.rd_bit_offset = 0,
			},
			{
				.reg_offset = 0x44,
				.bit_offset = 1,
				.bit_mask = 1,
				.rd_bit_offset = 4,
			},
			{
				.reg_offset = 0x44,
				.bit_offset = 2,
				.bit_mask = 1,
				.rd_bit_offset = 8,
			},
#if defined(CONFIG_ARCH_LOMBO_N7V3)
			{ /* USB1 */
				.reg_offset = 0x44,
				.bit_offset = 4,
				.bit_mask = 1,
				.rd_bit_offset = 16,
			},
#endif
#if defined(CONFIG_ARCH_LOMBO_N7V7)
			{ /* MCU */
				.reg_offset = 0x44,
				.bit_offset = 3,
				.bit_mask = 1,
				.rd_bit_offset = 12,
			},
#endif
			{
				.reg_offset = 0x44,
				.bit_offset = 5,
				.bit_mask = 1,
				.rd_bit_offset = 20,
			},
		},
		.name = {
			"USB0",
			"SD0",
			"SD1",
#if defined(CONFIG_ARCH_LOMBO_N7V3)
			"USB1",
#endif
#if defined(CONFIG_ARCH_LOMBO_N7V7)
			"MCU",
#endif
			"SD2"
		},
#if defined(CONFIG_ARCH_LOMBO_N7V3) || defined(CONFIG_ARCH_LOMBO_N7V7)
		.master_num = 5,
#else
		.master_num = 4,
#endif
	},
};
#elif defined(CONFIG_ARCH_LOMBO_N9V1)
const struct master_info memtrl_master_prio[] = {
	{
		.priority_root = {
			.reg_offset = 0,
			.bit_offset = 0,
			.bit_mask = 0x3ff, /* set 12bit */
		},
		.name = {
			"CPU",
		},
		.master_num = 1,
	},
	{
		.priority_root = {
			.reg_offset = 0x10,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.priority_sub = { /* sub arbiter0 */
			{
				.reg_offset = 0x10,
				.bit_offset = 0x0,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x10,
				.bit_offset = 0x4,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x10,
				.bit_offset = 0x8,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x10,
				.bit_offset = 0x12,
				.bit_mask = 0x7,
			},
		},
		.name = {
			"VC",
			"VGSS",
			"IVX",
			"VDC",
		},
		.master_num = 4,
	},
	{
		.priority_root = {
			.reg_offset = 0x20,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.name = {
			"AX0",
		},
		.master_num = 1,
	},
	{
		.priority_root = {
			.reg_offset = 0x30,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.name = {
			"VISS",
		},
		.master_num = 1,
	},
	{
		.priority_root = {
			.reg_offset = 0x40,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.name = {
			"GPU",
		},
		.master_num = 1,
	},
	{
		.priority_root = {
			.reg_offset = 0x50,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.name = {
			"DPU",
		},
		.master_num = 1,
	},
	{
		.priority_root = {
			.reg_offset = 0x60,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.priority_sub = { /* sub arbiter1 */
			{
				.reg_offset = 0x20,
				.bit_offset = 0x0,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x20,
				.bit_offset = 0x4,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x20,
				.bit_offset = 0x8,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x20,
				.bit_offset = 0x16,
				.bit_mask = 0x7,
			},
		},
		.name = {
			"DMA",
			"GMAC0",
			"GMAC1",
			"CE",
		},
		.master_num = 4,
	},
	{
		.priority_root = {
			.reg_offset = 0x70,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.name = {
			"AX1",
		},
		.master_num = 1,
	},
	{
		.priority_root = {
			.reg_offset = 0x80,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.priority_sub = { /* sub arbiter2 */
			{
				.reg_offset = 0x30,
				.bit_offset = 0,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x30,
				.bit_offset = 4,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x30,
				.bit_offset = 8,
				.bit_mask = 0x7,
			},
		},
		.name = {
			"HVC",
			"USB3_0",
			"USB3_1",
		},
		.master_num = 3,
	},
	{
		.priority_root = {
			.reg_offset = 0x90,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.priority_sub = { /* sub arbiter3 */
			{
				.reg_offset = 0x40,
				.bit_offset = 0,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x40,
				.bit_offset = 4,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x40,
				.bit_offset = 8,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x40,
				.bit_offset = 12,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x40,
				.bit_offset = 16,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x40,
				.bit_offset = 20,
				.bit_mask = 0x7,
			},
		},
		.name = {
			"USB0",
			"SD0",
			"SD1",
			"AMU",
			"USB1",
			"SD2"
		},
		.master_num = 6,
	},
};
#elif defined(CONFIG_ARCH_LOMBO_N9V3)
const struct master_info memtrl_master_prio[] = {
	{
		/* M0 */
		.priority_root = {
			.reg_offset = 0,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.name = {
			"CPU",
		},
		.master_num = 1,
	},
	{
		/* M1 */
		.priority_root = {
			.reg_offset = 0x10,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.priority_sub = {
			{
				.reg_offset = 0x10,
				.bit_offset = 0x0,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x10,
				.bit_offset = 0x4,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x10,
				.bit_offset = 0x8,
				.bit_mask = 0x7,
			},
		},
		.name = {
			"VC",
			"VGSS",
			"IVX",
		},
		.master_num = 3,
	},
	{
		/* M2 */
		.priority_root = {
			.reg_offset = 0x20,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.name = {
			"AX",
		},
		.master_num = 1,
	},
	{
		/* M3 */
		.priority_root = {
			.reg_offset = 0x30,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.name = {
			"VISS",
		},
		.master_num = 1,
	},
	{
		/* M5 */
		.priority_root = {
			.reg_offset = 0x50,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.name = {
			"DPU",
		},
		.master_num = 1,
	},
	{
		/* M6 */
		.priority_root = {
			.reg_offset = 0x60,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.priority_sub = {
			{
				.reg_offset = 0x20,
				.bit_offset = 0,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x20,
				.bit_offset = 4,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x20,
				.bit_offset = 8,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x20,
				.bit_offset = 12,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x20,
				.bit_offset = 16,
				.bit_mask = 0x7,
			},
		},
		.name = {
			"DMA",
			"GMAC0",
			"GMAC1",
			"I2CCQI",
			"CE",
		},
		.master_num = 5,
	},
	{
		/* M7 */
		.priority_root = {
			.reg_offset = 0x70,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.name = {
			"HVC",
		},
		.master_num = 1,
	},
	{
		/* M8 */
		.priority_root = {
			.reg_offset = 0x80,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.priority_sub = {
			{
				.reg_offset = 0x30,
				.bit_offset = 4,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x30,
				.bit_offset = 8,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x30,
				.bit_offset = 12,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x30,
				.bit_offset = 16,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x30,
				.bit_offset = 20,
				.bit_mask = 0x7,
			},
		},
		.name = {
			"USB3_0",
			"USB3_1",
			"PCIE0",
			"PCIE1",
			"SATA",
		},
		.master_num = 5,
	},
	{
		/* M9 */
		.priority_root = {
			.reg_offset = 0x90,
			.bit_offset = 0,
			.bit_mask = 0x3ff,
		},
		.priority_sub = {
			{
				.reg_offset = 0x40,
				.bit_offset = 0,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x40,
				.bit_offset = 4,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x40,
				.bit_offset = 8,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x40,
				.bit_offset = 16,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x40,
				.bit_offset = 20,
				.bit_mask = 0x7,
			},
			{
				.reg_offset = 0x40,
				.bit_offset = 24,
				.bit_mask = 0x7,
			},
		},
		.name = {
			"USB2_0",
			"SD0",
			"SD1",
			"USB2_1",
			"SD2",
			"SPI",
		},
		.master_num = 6,
	},
};
#endif

const struct master_prio_array master_prio_array = {
	.master_prio = memtrl_master_prio,
	.array_size = ARRAY_SIZE(memtrl_master_prio),
};

const struct bw_bits_name bwctrl_default[] = {
	{
		.name	= "timewindow",
		.ref	= "tw",
		.val	= 0x200,
	},
	{
		.name	= "datasize",
		.ref	= "ds",
		.val	= 0x400,
	},
	{
		.name	= "randmode",
		.ref	= "rm",
		.val	= 0x0,
	},
	{
		.name	= "ctrlmode",
		.ref	= "cm",
		.val	= 0x0,
	},
	{
		.name	= "randomseed",
		.ref	= "rs",
		.val	= 0x10,
	},
};

const struct bw_bits_name_array bw_bits_name_array = {
	.names = bwctrl_default,
	.array_size = ARRAY_SIZE(bwctrl_default),
};

#if defined(CONFIG_ARCH_LOMBO_N7V1)
const struct bwctrl_master_info bwctrl_masters[] = {
	{
		.name = "AX",
		.hwnum = BWCTRL_AX,
		.arbiter = NOC,
	},
	{
		.name = "VC",
		.hwnum = BWCTRL_VC,
		.arbiter = SARB,
	},
	{
		.name = "VDC",
		.hwnum = BWCTRL_VDC,
		.arbiter = SARB,
	},
};
#elif defined(CONFIG_ARCH_LOMBO_N7V3)
const struct bwctrl_master_info bwctrl_masters[] = {
	{
		.name = "AX0",
		.hwnum = BWCTRL_AX0,
		.arbiter = NOC,
	},
	{
		.name = "HVC",
		.hwnum = BWCTRL_HVC,
		.arbiter = NOC,
	},
	{
		.name = "MJPEG",
		.hwnum = BWCTRL_MPEG,
		.arbiter = SARB,
	},
	{
		.name = "VGSS",
		.hwnum = BWCTRL_VGSS,
		.arbiter = SARB,
	},
	{
		.name = "IVX",
		.hwnum = BWCTRL_IVX,
		.arbiter = SARB,
	},
};
#elif defined(CONFIG_ARCH_LOMBO_N7V5) || defined(CONFIG_ARCH_LOMBO_N5V1) \
	|| defined(CONFIG_ARCH_LOMBO_N7V7)
const struct bwctrl_master_info bwctrl_masters[] = {
	{
		.name = "AX0",
		.hwnum = BWCTRL_AX0,
		.arbiter = NOC,
	},
#ifdef CONFIG_ARCH_LOMBO_N7V7
	{
		.name = "HVX",
		.hwnum = BWCTRL_HVX,
		.arbiter = NOC,
	},
#endif
	{
		.name = "MJPEG",
		.hwnum = BWCTRL_MJEPG,
		.arbiter = SARB,
	},
	{
		.name = "VGSS",
		.hwnum = BWCTRL_VGSS,
		.arbiter = SARB,
	},
	{
		.name = "IVX",
		.hwnum = BWCTRL_IVX,
		.arbiter = SARB,
	},
};
#elif defined(CONFIG_ARCH_LOMBO_N9V1)
const struct bwctrl_master_info bwctrl_masters[] = {
	{
		.name = "AX0",
		.hwnum = BWCTRL_AX0,
		.arbiter = NOC,
	},
	{
		.name = "AX1",
		.hwnum = BWCTRL_AX1,
		.arbiter = NOC,
	},
	{
		.name = "GPU",
		.hwnum = BWCTRL_GPU,
		.arbiter = NOC,
	},
	{
		.name = "VC",
		.hwnum = BWCTRL_VC,
		.arbiter = SARB,
	},
	{
		.name = "VGSS",
		.hwnum = BWCTRL_VGSS,
		.arbiter = SARB,
	},
	{
		.name = "IVX",
		.hwnum = BWCTRL_IVX,
		.arbiter = SARB,
	},
	{
		.name = "VDC",
		.hwnum = BWCTRL_VDC,
		.arbiter = SARB,
	},
	{
		.name = "HVC",
		.hwnum = BWCTRL_HVC,
		.arbiter = SARB,
	},
	{
		.name = "USB3_0",
		.hwnum = BWCTRL_USB3_0,
		.arbiter = SARB,
	},
	{
		.name = "USB3_1",
		.hwnum = BWCTRL_USB3_1,
		.arbiter = SARB,
	},
};
#elif defined(CONFIG_ARCH_LOMBO_N9V3)
const struct bwctrl_master_info bwctrl_masters[] = {
	{
		.name = "AX",
		.hwnum = BWCTRL_AX,
		.arbiter = NOC,
	},
	{
		.name = "HVC",
		.hwnum = BWCTRL_HVC,
		.arbiter = NOC,
	},
	{
		.name = "VC",
		.hwnum = BWCTRL_VC,
		.arbiter = SARB,
	},
	{
		.name = "VGSS",
		.hwnum = BWCTRL_VGSS,
		.arbiter = SARB,
	},
	{
		.name = "IVX",
		.hwnum = BWCTRL_IVX,
		.arbiter = SARB,
	},
	{
		.name = "USB3_0",
		.hwnum = BWCTRL_USB3_0,
		.arbiter = SARB,
	},
	{
		.name = "PCIE0",
		.hwnum = BWCTRL_PCIE0,
		.arbiter = SARB,
	},
	{
		.name = "PCIE1",
		.hwnum = BWCTRL_PCIE1,
		.arbiter = SARB,
	},
	{
		.name = "SATA",
		.hwnum = BWCTRL_SATA,
		.arbiter = SARB,
	},
};
#endif

const struct bwctrl_masters_array bwctrl_masters_array = {
	.bwctrl_masters = bwctrl_masters,
	.array_size = ARRAY_SIZE(bwctrl_masters),
};

const struct data_unit_array *mctrl_dev_get_data_units(void)
{
	return &data_unit_array;
}

const struct flaw_unit_array *mctrl_dev_get_flaw_units(void)
{
	return &flaw_unit_array;
}

const struct sample_unit_array *mctrl_dev_get_sample_units(void)
{
	return &sample_unit_array;
}

const struct channel_info_array *mctrl_dev_get_master_channels(void)
{
	return &channel_info_array;
}

const struct master_prio_array *mctrl_dev_get_memtrl_master_prio(void)
{
	return &master_prio_array;
}

const struct bw_bits_name_array *mctrl_dev_get_bwctrl_bits(void)
{
	return &bw_bits_name_array;
}

const struct bwctrl_masters_array *mctrl_dev_get_bwctrl_masters(void)
{
	return &bwctrl_masters_array;
}
